package com.bytz.modules.cms.pay.chinapay.service.impl;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import com.bytz.common.exception.BytzBootException;
import com.bytz.modules.cms.common.exception.PayOverdueSoonException;
import com.bytz.modules.cms.order.entity.OrderPayDetail;
import com.bytz.modules.cms.order.model.PayNotifyResult;
import com.bytz.modules.cms.pay.chinapay.model.ChinaPayProperties;
import com.bytz.modules.cms.pay.chinapay.util.AcpService;
import com.bytz.modules.cms.pay.chinapay.util.ChinaPayBankUtil;
import com.bytz.modules.cms.pay.chinapay.util.ChinaPayResponseUtil;
import com.bytz.modules.cms.pay.service.ISpecificPayOnlineService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.Map;
import java.util.TreeMap;

/**
 * ChinaPay
 */
@Slf4j
@Service
public class ChinaPayServiceImpl implements ISpecificPayOnlineService {
    @Autowired
    private ChinaPayProperties chinaPayProperties;

    /**
     * 银联ChinaPay支付返回一个form表单
     */
    @Override
    public String startPayPage(OrderPayDetail payDetail) {
        log.info("####################开始支付####################");
        Map<String, Object> paramMap = new TreeMap<>();
        paramMap.put("Version", "20140728");
        //接入类型  0：商户身份接入（默认）1：机构身份接入
        paramMap.put("AccessType", "0");
        paramMap.put("MerId", chinaPayProperties.getMerId());
        paramMap.put("MerOrderNo", payDetail.getId());
        paramMap.put("TranDate", payDetail.getTranDate());
        paramMap.put("TranTime", DateUtil.format(LocalDateTime.now(), DatePattern.PURE_TIME_PATTERN));
        Duration duration = Duration.between(LocalDateTime.now(), payDetail.getExpirationTime());
        if (duration.toMinutes() < 1) {
            throw new PayOverdueSoonException("支付订单超时【当前日期（" + DateUtil.now() + "）已经超过过期时间");
        }

        String payTimeOut = String.valueOf(duration.toMinutes());
        // 超时时间 单位：分钟
        paramMap.put("PayTimeOut", payTimeOut);
        //单位：分
        paramMap.put("OrderAmt", payDetail.getPayAmount().multiply(new BigDecimal("100")).stripTrailingZeros().toPlainString());
        //交易类型，固定值
        paramMap.put("TranType", "0002");
        //业务类型，固定值
        paramMap.put("BusiType", "0001");
        paramMap.put("CommodityMsg", payDetail.getCommodityMsg());
        //支付异步通知地址:用来接收交易结果后台通知的地址
        paramMap.put("MerBgUrl", chinaPayProperties.getMerBgUrl());
        //支付完成跳转的页面
        paramMap.put("MerPageUrl", chinaPayProperties.getMerPageUrl());
        // 钓鱼功能暂不用
        // paramMap.put("RemoteAddr", "xxxIP");
        log.info("==============订单号===========:" + paramMap.get("MerOrderNo"));
        // 设置签名
        AcpService.putSign(paramMap);
        log.info("####################请求总参数####################");
        log.info(paramMap.toString());
        //必须构建成【自动提交form表单】html，返回商城前端自动跳转到网银支付页面
        String buildRequest = AcpService.buildRequest(paramMap, chinaPayProperties.getFrontRequestUrl(), "post");
        log.info("####################构建的表单####################");
        log.info(buildRequest);

        return buildRequest;
    }


    /**
     * 银联ChinaPay支付返回通知前台
     */
    @Override
    public PayNotifyResult parseFrontNotify(HttpServletRequest request) {
        // 获取银联通知服务器发送的后台通知参数
        Map<String, String> reqParam = AcpService.getAllRequestParam(request, "0");
        //打印参数
        log.info(reqParam.toString());

        return verifyAndParse(reqParam);
    }

    /**
     * 银联ChinaPay支付返回通知后台
     */
    @Override
    public PayNotifyResult parseBackNotify(HttpServletRequest request) {
        // 获取银联通知服务器发送的后台通知参数
        Map<String, String> reqParam = AcpService.getAllRequestParam(request, "1");
        //打印参数
        log.info(reqParam.toString());

        return verifyAndParse(reqParam);
    }

    private PayNotifyResult verifyAndParse(Map<String, String> reqParam) {
        AcpService.verifyNotify(reqParam);

        PayNotifyResult result = new PayNotifyResult();
        String orderStatus = reqParam.get("OrderStatus");
        result.setCode(orderStatus);
        result.setPayResponse(ChinaPayResponseUtil.getPayResponse(orderStatus));
        result.setPaySource(ChinaPayBankUtil.getBankName(reqParam.get("BankInstNo")));
        result.setPayDetailId(reqParam.get("MerOrderNo"));
        result.setCompleteDate(reqParam.get("CompleteDate"));
        if (reqParam.get("CompleteDate") != null && reqParam.get("CompleteTime") != null) {
            result.setCompleteDateTime(reqParam.get("CompleteDate") + reqParam.get("CompleteTime"));
        }
        result.setTransactionNumber(reqParam.get("AcqSeqId"));
        result.setTranDate(reqParam.get("TranDate"));
        result.setOrderAmt(reqParam.get("OrderAmt"));
        result.setAcqDate(reqParam.get("AcqDate"));
        result.setBankInstNo(reqParam.get("BankInstNo"));
        log.info("####################PayNotifyResult####################");
        log.info(result.toString());

        return result;
    }

    /**
     * 银联ChinaPay支付返回一个form表单
     */
    @Override
    public PayNotifyResult queryPayResult(OrderPayDetail payDetail) {
        log.info("####################开始查询####################");
        Map<String, Object> paramMap = new TreeMap<>();
        paramMap.put("Version", "20140728");
        //交易类型，固定值：0502
        paramMap.put("TranType", "0502");
        //业务类型，固定值
        paramMap.put("BusiType", "0001");
        // 商户订单号可包含字母和数字，与 MerId 和 TranDate 一起，ChinaPay是根据这三个字段唯一确定一笔订单
        paramMap.put("MerOrderNo", payDetail.getId());
        paramMap.put("MerId", chinaPayProperties.getMerId());
        // 原交易日期 ， 格式 ：yyyyMMdd
        paramMap.put("TranDate", payDetail.getTranDate());

        // 设置签名
        AcpService.putSign(paramMap);

        log.info(paramMap.toString());
        String resp = AcpService.doPostSSL(chinaPayProperties.getSingleQueryUrl(), paramMap, Collections.emptyMap());
        if (resp == null) {
            throw new BytzBootException("接口异常：查询未返回内容");
        }

        log.info("################交易查询结果：{}", resp);
        // 解析同步应答字段
        Map<String, String> resultMap = AcpService.getRespMap(resp);

        //返回数据验签
        AcpService.verifyNotify(resultMap);


        return verifyAndParse(resultMap);
    }

}